<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="author" content="GoJun" />
	
	
	
	<title>通俗易懂了解 Android 设计模式 - 备忘录模式 ｜ GoJun</title>
	
    
    
    <meta name="description" content="介绍 备忘录模式是三大设计模式中的行为型模式一种，用于保存对象当前状态，并且在之后可以重新恢复此状态。 值得注意的是备忘录模式实现方式要保证保存的对象状态不能被对象从外部访问，目的保护好被保存的这些对象状" />
    

    
    
    <meta name="keywords" content="Hugo, theme, zozo" />
    

	
    
    <link rel="shortcut icon" href="https://gojun.me/images/favicon.ico" />

    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.mecss/normalize.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/animate.css@4.1.0/animate.min.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.me/css/zozo.css" />
	<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.me/css/highlight.css" />

    
    
</head>

<body>
    <div class="main animate__animated animate__fadeInDown">
        <div class="nav_container animated fadeInDown">
    <div class="site_nav" id="site_nav">
        <ul>
            
            <li>
                <a href="/">Home</a>
            </li>
            
            <li>
                <a href="/posts/">Archive</a>
            </li>
            
            <li>
                <a href="/tags/">Tags</a>
            </li>
            
            <li>
                <a href="/projects/">Projects</a>
            </li>
            
        </ul>
    </div>
    <div class="menu_icon">
        <a id="menu_icon"><i class="ri-menu-line"></i></a>
    </div>
</div>
        <div class="header animated fadeInDown">
    <div class="site_title_container">
        <div class="site_title">
            <h1>
                <a href="https://gojun.me">
                    <span>GoJun</span>
                </a>
            </h1>
        </div>
        <div class="description">
            <p class="sub_title">为向往生活努力奋斗！</p>
            <div class="my_socials">
                
                
                <a href="https://github.com/freelander" title="github" target="_blank"><i class="ri-github-fill"></i></a>
                
                
                <a href="https://gojun.me/index.xml" type="application/rss+xml" title="rss" target="_blank"><i
                        class="ri-rss-fill"></i></a>
            </div>
        </div>
    </div>
</div>
        <div class="content">
            <div class="post_page">
                <div class="post animate__animated animate__fadeInDown">
                    <div class="post_title post_detail_title">
                        <h2><a href='/posts/android-memento-mode/'>通俗易懂了解 Android 设计模式 - 备忘录模式</a></h2>
                        <span class="date">2021.08.29</span>
                    </div>
                    <div class="post_content markdown"><h3 id="介绍">介绍</h3>
<p>备忘录模式是三大设计模式中的行为型模式一种，用于保存对象当前状态，并且在之后可以重新恢复此状态。</p>
<p>值得注意的是备忘录模式实现方式要保证保存的对象状态不能被对象从外部访问，目的保护好被保存的这些对象状态的完整性以及内部实现不向外部暴露。</p>
<h3 id="定义">定义</h3>
<p>在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态，这样以后就可将该对象恢复到原先保存的状态。</p>
<p>通俗理解，备忘录模式就是对一个对象的备份模式，提供一种程序数据的备份方法。</p>
<h3 id="使用场景">使用场景</h3>
<ul>
<li>需要保存或恢复一个对象在某一个时刻的数据状态时。</li>
</ul>
<h3 id="uml-类图">UML 类图</h3>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2021/08/android-memento-mode-01.png">
<img src="/images/2021/08/android-memento-mode-01.png" alt="img"  />
</a>
</div>

</p>
<h4 id="角色解释">角色解释：</h4>
<p>Memento：备忘录角色，负责存储 Originator 的内部状态，并且可以防止 Originator 以外的对象访问 Memento。</p>
<p>Caretaker：管理者角色，负责存储备忘录，不能对备忘录的内容进行操作和访问，只能将备忘录传递给其他对象。</p>
<p>Originator：发起者角色，负责创建和恢复记录的数据。同时 Originator 还可以根据需要决定 Memento 存储自身的哪些内部状态。</p>
<h3 id="举个例子">举个例子</h3>
<p>场景：在手机电商 App 应用上，用户正在对某个商品进行编辑评论时，突然接到来电，此时需要存储下当前已编辑的评论内容，等待用户接完电话后恢复继续进行评论。</p>
<h4 id="备忘录角色">备忘录角色</h4>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="cm">/**
</span><span class="cm"> * Description: 备忘录角色，存储已输入的评论内容及时间
</span><span class="cm"> *
</span><span class="cm"> * @author Jun 2021/8/29
</span><span class="cm"> */</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Memento</span> <span class="o">{</span>

    <span class="c1">// 输入的评论内容
</span><span class="c1"></span>    <span class="kd">private</span> <span class="n">String</span> <span class="n">writeCommentContent</span><span class="o">;</span>
    <span class="c1">// 评论时间
</span><span class="c1"></span>    <span class="kd">private</span> <span class="n">String</span> <span class="n">time</span><span class="o">;</span>

    <span class="kd">public</span> <span class="n">String</span> <span class="nf">getWriteCommentContent</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">writeCommentContent</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setWriteCommentContent</span><span class="o">(</span><span class="n">String</span> <span class="n">writeCommentContent</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">writeCommentContent</span> <span class="o">=</span> <span class="n">writeCommentContent</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="n">String</span> <span class="nf">getTime</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">time</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setTime</span><span class="o">(</span><span class="n">String</span> <span class="n">time</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">time</span> <span class="o">=</span> <span class="n">time</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div><h4 id="管理者角色">管理者角色</h4>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="cm">/**
</span><span class="cm"> * Description: 管理者角色，负责存储备忘录角色
</span><span class="cm"> *
</span><span class="cm"> * @author Jun 2021/8/29
</span><span class="cm"> */</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Caretaker</span> <span class="o">{</span>

   <span class="kd">private</span> <span class="n">Memento</span> <span class="n">mMemento</span><span class="o">;</span>

    <span class="kd">public</span> <span class="n">Memento</span> <span class="nf">getMemento</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">mMemento</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setMemento</span><span class="o">(</span><span class="n">Memento</span> <span class="n">memento</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">mMemento</span> <span class="o">=</span> <span class="n">memento</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div><h4 id="发起者角色">发起者角色</h4>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="kn">import</span> <span class="nn">java.util.Date</span><span class="o">;</span>

<span class="cm">/**
</span><span class="cm"> * Description: 发起者角色，负责创建、保存及恢复记录的评论内容
</span><span class="cm"> *
</span><span class="cm"> * @author Jun 2021/8/29
</span><span class="cm"> */</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Originator</span> <span class="o">{</span>

    <span class="c1">// 输入的评论内容
</span><span class="c1"></span>    <span class="kd">private</span> <span class="n">String</span> <span class="n">writeCommentContent</span><span class="o">;</span>
    <span class="c1">// 评论时间
</span><span class="c1"></span>    <span class="kd">private</span> <span class="n">String</span> <span class="n">time</span><span class="o">;</span>

    <span class="kd">public</span> <span class="n">String</span> <span class="nf">getWriteCommentContent</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">writeCommentContent</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setWriteCommentContent</span><span class="o">(</span><span class="n">String</span> <span class="n">writeCommentContent</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">writeCommentContent</span> <span class="o">=</span> <span class="n">writeCommentContent</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="n">String</span> <span class="nf">getTime</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">time</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setTime</span><span class="o">(</span><span class="n">String</span> <span class="n">time</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">time</span> <span class="o">=</span> <span class="n">time</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">String</span> <span class="nf">toString</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="s">&#34;在 &#34;</span> <span class="o">+</span> <span class="n">time</span> <span class="o">+</span> <span class="s">&#34; 对商品进行评论：&#34;</span> <span class="o">+</span> <span class="n">writeCommentContent</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="c1">// 开始编写评论内容
</span><span class="c1"></span>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">startWriteComment</span><span class="o">(</span><span class="n">String</span> <span class="n">content</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">writeCommentContent</span> <span class="o">=</span> <span class="n">content</span><span class="o">;</span>
        <span class="k">this</span><span class="o">.</span><span class="na">time</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Date</span><span class="o">(</span><span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">()).</span><span class="na">toString</span><span class="o">();</span>
        <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">&#34;开始编写评论: &#34;</span> <span class="o">+</span> <span class="n">toString</span><span class="o">());</span>
    <span class="o">}</span>

    <span class="c1">// 停止编写评论内容
</span><span class="c1"></span>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">stopWriteComment</span><span class="o">()</span> <span class="o">{</span>
        <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">&#34;停止编写评论&#34;</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="c1">// 保存当前编写的评论内容
</span><span class="c1"></span>    <span class="kd">public</span> <span class="n">Memento</span> <span class="nf">saveWrite</span><span class="o">()</span> <span class="o">{</span>
        <span class="n">Memento</span> <span class="n">memento</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Memento</span><span class="o">();</span>
        <span class="n">memento</span><span class="o">.</span><span class="na">setTime</span><span class="o">(</span><span class="n">time</span><span class="o">);</span>
        <span class="n">memento</span><span class="o">.</span><span class="na">setWriteCommentContent</span><span class="o">(</span><span class="n">writeCommentContent</span><span class="o">);</span>
        <span class="k">return</span> <span class="n">memento</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="c1">// 恢复上次编写评论
</span><span class="c1"></span>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">restoreWrite</span><span class="o">(</span><span class="n">Memento</span> <span class="n">memento</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">writeCommentContent</span> <span class="o">=</span> <span class="n">memento</span><span class="o">.</span><span class="na">getWriteCommentContent</span><span class="o">();</span>
        <span class="k">this</span><span class="o">.</span><span class="na">time</span> <span class="o">=</span> <span class="n">memento</span><span class="o">.</span><span class="na">getTime</span><span class="o">();</span>
        <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">&#34;恢复上次编写评论: &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="o">.</span><span class="na">toString</span><span class="o">());</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div><h4 id="测试">测试</h4>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="cm">/**
</span><span class="cm"> * Description: 测试
</span><span class="cm"> *
</span><span class="cm"> * @author Jun 2021/8/29
</span><span class="cm"> */</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">MementoDemo</span> <span class="o">{</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
        <span class="c1">// 用户开始编写商品评论信息
</span><span class="c1"></span>        <span class="n">Originator</span> <span class="n">originator</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Originator</span><span class="o">();</span>
        <span class="n">originator</span><span class="o">.</span><span class="na">startWriteComment</span><span class="o">(</span><span class="s">&#34;裙子尺寸合适，没有色差，穿上很好看！&#34;</span><span class="o">);</span>

        <span class="c1">// 突然用户接到来电停止评论
</span><span class="c1"></span>        <span class="n">originator</span><span class="o">.</span><span class="na">stopWriteComment</span><span class="o">();</span>

        <span class="c1">// 此时程序需保存用户编写的评论内容
</span><span class="c1"></span>        <span class="n">Caretaker</span> <span class="n">caretaker</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Caretaker</span><span class="o">();</span>
        <span class="n">caretaker</span><span class="o">.</span><span class="na">setMemento</span><span class="o">(</span><span class="n">originator</span><span class="o">.</span><span class="na">saveWrite</span><span class="o">());</span>

        <span class="c1">// 用户通话结束回到界面继续编写的评论内容
</span><span class="c1"></span>        <span class="n">originator</span><span class="o">.</span><span class="na">restoreWrite</span><span class="o">(</span><span class="n">caretaker</span><span class="o">.</span><span class="na">getMemento</span><span class="o">());</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div><h4 id="结果">结果</h4>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2021/08/android-memento-mode-02.png">
<img src="/images/2021/08/android-memento-mode-02.png" alt="img"  />
</a>
</div>

</p>
<h3 id="总结">总结</h3>
<p>通过上面场景了解到备忘录模式不仅在思想上简单，并且在代码的使用上也很简单，通过用单独的类来保存和读取状态，这样就避免直接访问数据以及其中的内部实现。</p>
<p>发起角色 Originator 状态的备份与恢复，自身不需要管理与操作，而是由 Caretaker(客户端) 自行按需要处理，当发起角色的状态出现问题时，Caretaker 可以很轻松将它恢复。</p>
<p>在 Android 源码中的使用到备忘录模式的，当属 Activity 中的 onSaveInstanceState()，onRestoreInstanceState() 两个方法，
在非主动退出或跳转到其他 Activity 时，触发 onSaveInstanceState() 方法进行数据备份，下次恢复启动 Activity 时读取备份的数据。</p>
<h4 id="优点">优点</h4>
<ul>
<li>提供了一种状态备份恢复机制，使用户能方便的回到某个时刻的状态；</li>
<li>实现了信息的封装，使用户不需要关心状态的保存细节。</li>
</ul>
<h4 id="缺点">缺点</h4>
<ul>
<li>每一次保存都会消耗一定的内存，当类的成员变量过多，势必会消耗更多的资源。</li>
</ul>
<h3 id="参考链接">参考链接</h3>
<ul>
<li><a href="https://medium.com/@sawomirkowalski/design-patterns-memento-f9fc1e127316">Design patterns: Memento</a></li>
<li><a href="https://cloud.tencent.com/developer/article/1735840">Android 编程设计模式之备忘录模式详解</a></li>
</ul>
</div>
                    <div class="post_footer">
                        
                        <div class="meta">
                            <div class="info">
                                <span class="field tags">
                                    <i class="ri-stack-line"></i>
                                    
                                    <a href="https://gojun.me/tags/android/">Android</a>
                                    
                                    <a href="https://gojun.me/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/">设计模式</a>
                                    
                                </span>
                            </div>
                        </div>
                        
                    </div>
                </div>
                
                
                <div class="doc_comments"></div>
                
            </div>
        </div>
    </div>
    <a id="back_to_top" href="#" class="back_to_top"><i class="ri-arrow-up-s-line"></i></a>
    <footer class="footer">
    <div class="footer_slogan">
        <span></span>
    </div>
</footer>
    <script src="https://gojun.me/js/jquery-3.5.1.min.js"></script>
<link href="https://gojun.me/css/fancybox.min.css" rel="stylesheet">
<script src="https://gojun.me/js/fancybox.min.js"></script>
<script src="https://gojun.me/js/zozo.js"></script>


<script type="text/javascript" async
    src="https://cdn.bootcss.com/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
        MathJax.Hub.Config({
            tex2jax: {
                inlineMath: [['$', '$'], ['\\(', '\\)']],
                displayMath: [['$$', '$$'], ['\[\[', '\]\]']],
                processEscapes: true,
                processEnvironments: true,
                skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
                TeX: {
                    equationNumbers: { autoNumber: "AMS" },
                    extensions: ["AMSmath.js", "AMSsymbols.js"]
                }
            }
        });

        MathJax.Hub.Queue(function () {
            
            
            
            var all = MathJax.Hub.getAllJax(), i;
            for (i = 0; i < all.length; i += 1) {
                all[i].SourceElement().parentNode.className += ' has-jax';
            }
        });
    </script>

<style>
    code.has-jax {
        font: inherit;
        font-size: 100%;
        background: inherit;
        border: inherit;
        color: #515151;
    }
</style>



<script type="application/javascript">
var doNotTrack = false;
if (!doNotTrack) {
	window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
	ga('create', 'UA-142037913-1', 'auto');
	
	ga('send', 'pageview');
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>

</body>

</html>